import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:animal/ui/login/page/login_page.dart';
import 'package:animal/ui/login/page/short_login_page.dart';
import 'package:animal/utils/LogUtil.dart';
import 'package:animal/utils/sputils/sp_config.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart' as g;
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart';

import 'NWApi.dart';
import 'default.dart';

///http请求
class HttpManager {
  // static const CONTENT_TYPE = "application/json";

  static const CONTENT_TYPE = "application/x-www-form-urlencoded";

  static Dio? dio;
  static const int CONNECR_TIME_OUT = 10000;
  static const int RECIVE_TIME_OUT = 10000;
  static final Map<String, CancelToken> _cancelTokens = <String, CancelToken>{};

  static String? api;

  HttpManager._internal() {
    initDio();
  }

  static final HttpManager _httpManger = HttpManager._internal();

  factory HttpManager() {
    return _httpManger;
  }

  //get请求
  PublishSubject<Default<T>> get<T>(String url, {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "get", queryParameters, isCancelable);
  }

  //post请求
  PublishSubject<Default<T>> post<T>(String url, {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "post", queryParameters, isCancelable);
  }

  //post请求 上传文件
  PublishSubject<Default<T>> postUploadFile<T>(String url,
      {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "postFile", FormData.fromMap(queryParameters!), isCancelable);
  }

  //put请求
  PublishSubject<Default<T>> put<T>(String url, {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "put", queryParameters, isCancelable);
  }

  //deletet请求
  PublishSubject<Default<T>> delete<T>(String url, {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "delete", FormData.fromMap(queryParameters!), isCancelable);
  }

  /// 参数说明  url 请求路径
  /// queryParamerers  是 请求参数
  /// isCancelable 是设置改请求是否能被取消
  PublishSubject<Default<T>> _requstHttp<T>(String url, [String? type, queryParameters, bool? isCancelable]) {
    Future future;
    PublishSubject<Default<T>> publishSubject = PublishSubject<Default<T>>();
    CancelToken? cancelToken;
    //保存取消token
    if (isCancelable!) {
      //如果需要取消网络请求，在这里标记cancelToken
      // cancelToken = _cancelTokens[g.Get.currentRoute] == null ? CancelToken() : _cancelTokens[g.Get.currentRoute];
      // _cancelTokens[g.Get.currentRoute] = cancelToken;
      // debugPrint("当前路由：${g.Get.currentRoute}");
    }
    if (type == "get") {
      future = dio!.get(url, queryParameters: queryParameters, cancelToken: cancelToken);
    } else if (type == "put") {
      future = dio!.put(url, data: queryParameters, cancelToken: cancelToken);
    } else if (type == "post" || type == "postFile") {
      future = dio!.post(url, data: queryParameters, cancelToken: cancelToken);
    } else if (type == "delete") {
      future = dio!.delete(url, data: queryParameters, cancelToken: cancelToken);
    } else {
      future = dio!.patch(url, data: queryParameters, cancelToken: cancelToken);
    }
    if (type != "postFile") debugPrint("请求参数：${json.encode(queryParameters)}");
    debugPrint("请求地址：${api??NWApi.baseApi}$url  请求方式：$type");
    future.then((da) {
      Response data = da;
      LogUtil.e(("请求地址：$url，返回数据：$data"));
      if (data.headers.value("status") == "401") {
        //token过期 提示并进入登录界面
        return;
      }
      //需要先过滤 error ， 根据和后台的 约定 ， 搞清楚什么是失败
      int code = json.decode(data.toString())["status"];
      if (code != 0) {
        debugPrint("请求错误${json.decode(data.toString())}");
        callError(
          publishSubject,
          MyError(code, json.decode(data.toString())["message"]),
        );
        // if(code == 1){
        //   g.Get.offAll(const ShortLoginPage());
        //   SmartDialog.showToast("登录已过期，请重新登录");
        // }
      } else {
        //解析
        // debugPrint(json.decode(data.toString()));
        publishSubject.add(Default<T>.fromJson(json.decode(data.toString())));
        publishSubject.close();
      }
    }).catchError((err) {
      debugPrint(err.toString());
      //接口抛出异常，根据不同得返回做对应得操作，最后统一返回MyError
      if (err.toString() != "DioError [DioErrorType.CANCEL]: ") {
        if (err is DioError) {
          var error = json.decode(err.response.toString());
          if (error == null) {
            callError(publishSubject, MyError(-1, "请求错误"));
          } else {
            if (error['status'] == 401) {
              return;
            }
            debugPrint("请求错误1：${error['message']} code:${error['status']}");
            callError(publishSubject, MyError(error['status'], error['message']));
          }
        } else {
          debugPrint("请求错误2：${err.toString()}");
          callError(publishSubject, MyError(1, err.toString()));
        }
      } else {
        debugPrint("这个网络请求的取消操作被拦截了");
      }
      if(err.toString().contains("DioError [DioErrorType.connectTimeout]")){
        callError(publishSubject, MyError(-1, "网络超时，请稍候重试"));
        return;
      }
    });
    return publishSubject;
  }

  ///请求错误以后 做的一些事情
  void callError(PublishSubject publishSubject, MyError error) {
    publishSubject.addError(error);
    publishSubject.close();
  }

  ///取消请求
  static void cancelHttp(String tag) {
    debugPrint("$tag ${_cancelTokens.containsKey(tag)}");
    if (_cancelTokens.containsKey(tag)) {
      if (!_cancelTokens[tag]!.isCancelled) {
        _cancelTokens[tag]!.cancel();
      }
      _cancelTokens.remove(tag);
    }
  }

  ///配置dio
  void initDio() {
    dio = Dio();
    //服务器地址
    dio!.options.baseUrl = api??NWApi.baseApi;
    debugPrint("这里是我的：${dio!.options.baseUrl}");
    //请求超时的时间
    dio!.options.connectTimeout = CONNECR_TIME_OUT;
    //接收超时的时间
    dio!.options.receiveTimeout = RECIVE_TIME_OUT;
    dio!.options.contentType = CONTENT_TYPE;

    /// 添加拦截器
    dio!.interceptors.add(MyIntercept());
  }
}

class MyError {
  int? state;
  String? message;

  MyError(this.state, this.message);
}

///在请求之前的拦截器，你可以在里面做一些需要的操作
class MyIntercept extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    debugPrint("请求token：${SpConfig().getUserToken()}");
    //配置请求头
    options.headers.addAll({
      "authKey": "${SpConfig().getUserToken()}",
      "app-version":"1.0.0",
      "device-version":"${SpConfig().getDeviceVersion()}",
      "user-agent":Platform.isAndroid?"android":"ios",
      "device_id":"${SpConfig().getAndroidProduct()}_${SpConfig().getUserId()}"
    });
    // LogUtil.e("请求头信息：${jsonEncode(options.headers)}");
    super.onRequest(options, handler);
  }
}
